package vlms.dao;

import java.sql.*;
import java.sql.Date;
import java.util.*;

import vlms.bean.IssuedMovie;
import vlms.bean.Movie;
import vlms.bean.Person;
import vlms.exception.IssuedmovieException;
import vlms.exception.MovieException;
import vlms.exception.PersonException;
import vlms.util.DateConvert;
import vlms.util.JDBCConnectionDriver;

public class MovieDAO  {
	
	static HashMap<Integer, Movie> listByMovieId;
	static HashMap<String, LinkedList<Movie>> listByMovieName;
	static HashMap<String, LinkedList<Movie>> listByMovieBanner;
	static HashMap<String, LinkedList<Movie>> listByMovieCategory;
	
	//Static Method Starts
	private static void staticPopulateVO(Movie dto, ResultSet rs) throws SQLException {
		dto.setMovieid(rs.getInt("movieId"));
		dto.setMoviename(rs.getString("movieName"));
		dto.setMoviebanner(rs.getString("movieBanner"));
		dto.setReleasedate(rs.getDate("releaseDate"));
		dto.setRentamount(rs.getInt("rentAmount"));
		dto.setCategory(rs.getString("category"));
		dto.setCopiesavailable(rs.getInt("copiesAvailable"));

	}
	
	private static void initializeList(Connection con)
	{
		listByMovieId=new HashMap<Integer, Movie>();
		listByMovieName=new HashMap<String, LinkedList<Movie>>();
		listByMovieBanner=new HashMap<String, LinkedList<Movie>>();
		listByMovieCategory=new HashMap<String, LinkedList<Movie>>();
		
		try {
			PreparedStatement stmt = null;
			ResultSet rs = null;
			
			String SQL_STATEMENT = "Select movieId, movieName, movieBanner, releaseDate, rentAmount, category, copiesAvailable from movie";
			stmt = con.prepareStatement(SQL_STATEMENT);
			rs = stmt.executeQuery();

			
			while (rs.next()) {
				Movie dto=new Movie();
				staticPopulateVO(dto, rs);		
				
				listByMovieId.put(new Integer(dto.getMovieid()), dto);
				
				if(!listByMovieName.containsKey(dto.getMoviename())) {
					LinkedList<Movie> movieList = new LinkedList<Movie>();
					listByMovieName.put(dto.getMoviename(), movieList);
				}
				listByMovieName.get(dto.getMoviename()).add(dto);
				
				if(!listByMovieBanner.containsKey(dto.getMoviebanner())) {
					LinkedList<Movie> movieList = new LinkedList<Movie>();
					listByMovieBanner.put(dto.getMoviebanner(), movieList);
				}
				listByMovieBanner.get(dto.getMoviebanner()).add(dto);
				
				
				if(!listByMovieCategory.containsKey(dto.getCategory())) {
					LinkedList<Movie> movieList = new LinkedList<Movie>();
					listByMovieCategory.put(dto.getCategory(), movieList);
				}
				listByMovieCategory.get(dto.getCategory()).add(dto);
				
				
				
			}				
		}			
		catch(SQLException se) {
		
			System.out.println("Exception "+se+ " occured in the system." +
							   " Failed to initialize the list.");
			
		}
	
	}
	
	static 
	{
		Connection con=null;
		try {
			/*
			try {
				//
				new JDBCConnectionDriver("com.mysql.jdbc.Driver", "jdbc:mysql://localhost:3306/vlmsdb", "root", "root", 10);
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			*/
			con = DriverManager.getConnection("jdbc:user_mysql:");
			initializeList(con);
			//con.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		finally
		{
			try {
				con.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	//Static Method Ends

	public int delete(int movieId, Connection con) throws MovieException, SQLException {
		PreparedStatement ps = null;
		
			ps = con.prepareStatement("delete from  MOVIE where movieId = ?");
			ps.setInt(1, movieId);
			int result=ps.executeUpdate();
			if(result <= 0)
			{
				throw new MovieException("No movie found in the system.");
			}
			Movie movieObj=listByMovieId.get(movieId);
			
			
			listByMovieName.get(movieObj.getMoviename()).remove(movieObj);
			listByMovieBanner.get(movieObj.getMoviebanner()).remove(movieObj);
			listByMovieCategory.get(movieObj.getCategory()).remove(movieObj);
			listByMovieId.remove(movieId);
			
			
			
			return result;
	}

	
	//Find fields which are updated after last read
	private HashMap<String,Object> findUpdatedFields(Movie newMovieObj, Movie listMovieObject) {
		
		HashMap<String,Object> updatedFieldsHashMap = new HashMap<String,Object>(); 
		
		if(!newMovieObj.getMoviename().equals(listMovieObject.getMoviename())) {
			updatedFieldsHashMap.put("movieName", newMovieObj.getMoviename());
		}
		
		if(!newMovieObj.getMoviebanner().equals(listMovieObject.getMoviebanner())) {
			updatedFieldsHashMap.put("movieBanner", newMovieObj.getMoviebanner());
		}
		
			
		if(newMovieObj.getReleasedate().compareTo(listMovieObject.getReleasedate()) !=0) {
			updatedFieldsHashMap.put("releaseDate", newMovieObj.getReleasedate());
		}
 		
		if(newMovieObj.getRentamount() != listMovieObject.getRentamount()) {
			updatedFieldsHashMap.put("rentAmount", newMovieObj.getRentamount());
		}
		
		if(!newMovieObj.getCategory().equals(listMovieObject.getCategory())) {
			updatedFieldsHashMap.put("category", newMovieObj.getCategory());
		}
		
		if(newMovieObj.getCopiesavailable() != listMovieObject.getCopiesavailable()) {
			updatedFieldsHashMap.put("copiesAvailable", newMovieObj.getCopiesavailable());
		}
		
		return updatedFieldsHashMap;
		
	}
	
	public int update(int movieId, Movie movie, Connection con)
			throws MovieException, SQLException {
		
		PreparedStatement ps = null;
		//Account listAccountObject = listByPersonId.get(personId);
		Movie listMovieObj = listByMovieId.get(movie.getMovieid()); 
		String fieldsValue = null;
		String sqlQuery;
		int rowsUpdated=0;
		if(listMovieObj != null) {
			
			HashMap<String,Object> updatedFieldsHashMap = findUpdatedFields(movie,listMovieObj);
			
			Set<String> keys = updatedFieldsHashMap.keySet();
			
			Iterator<String> it = keys.iterator();	
			System.out.println("" + keys.toString());
			while(it.hasNext()) {
				System.out.println("" + keys.toString());
				String value=it.next();
				if(fieldsValue != null) 
				
					fieldsValue += "," + value + " = '" + updatedFieldsHashMap.get(value) + "'";
				else
					fieldsValue = value + " = '" + updatedFieldsHashMap.get(value) + "'";
				
				if(fieldsValue != null) {
					System.out.println(fieldsValue);
					sqlQuery = "update MOVIE set " + fieldsValue + " where movieId = ?";
					
					ps = con.prepareStatement(sqlQuery);
					ps.setInt(1, movie.getMovieid());
					rowsUpdated = ps.executeUpdate();
					listByMovieId.put(movieId, movie);
				}
			}
			
		}
		else
		{
			sqlQuery = "update MOVIE set MOVIENAME = '"+ movie.getMoviename() + "', MOVIEBANNER = '"
			+ movie.getMoviebanner() + "', RELEASEDATE = '"
			+ DateConvert.convertUtilToSQLdate(movie.getReleasedate())  + "', RENTAMOUNT = '"
			 + movie.getRentamount() + "', CATEGORY = '"
				+ movie.getCategory()  + "', COPIESAVAILABLE = '"
				+ movie.getCopiesavailable() +"' WHERE movieId = ?";
			System.out.println(sqlQuery);
			
			ps = con.prepareStatement(sqlQuery);
			ps.setInt(1, movieId);
			rowsUpdated = ps.executeUpdate();
			
		    System.out.println(rowsUpdated);
			if(rowsUpdated <= 0) {
				throw new MovieException("No Movie found in the system");
			}
			else
			{
				
				
				Movie tempMovieObj=listByMovieId.get(movieId);
				
				
				
				LinkedList<Movie> movieList = new LinkedList<Movie>();
				movieList=listByMovieName.get(tempMovieObj.getMoviename());
				movieList.remove(tempMovieObj);
				
				if(!listByMovieName.containsKey(movie.getMoviename())) {
					LinkedList<Movie> list = new LinkedList<Movie>();
					movieList.add(movie);
					listByMovieName.put(movie.getMoviename(), list);
				}
				else
				{
					listByMovieName.get(movie.getMoviename()).add(movie);
				}
				
				LinkedList<Movie> movieList1 = new LinkedList<Movie>();
				movieList1=listByMovieBanner.get(tempMovieObj.getMoviebanner());
				movieList1.remove(tempMovieObj);
				
				if(!listByMovieBanner.containsKey(movie.getMoviebanner())) {
					LinkedList<Movie> list = new LinkedList<Movie>();
					movieList1.add(movie);
					listByMovieBanner.put(movie.getMoviebanner(), list);
				}
				else
				{
					listByMovieBanner.get(movie.getMoviebanner()).add(movie);
				}
				
				LinkedList<Movie> movieList2 = new LinkedList<Movie>();
				movieList2=listByMovieCategory.get(tempMovieObj.getCategory());
				movieList2.remove(tempMovieObj);
				
				if(!listByMovieCategory.containsKey(movie.getCategory())) {
					LinkedList<Movie> list = new LinkedList<Movie>();
					movieList2.add(movie);
					listByMovieCategory.put(movie.getCategory(), list);
				}
				else
				{
					listByMovieCategory.get(movie.getCategory()).add(movie);
				}
				
				listByMovieId.remove(movieId);
				listByMovieId.put(movieId, movie);
				
				
							
			}
			
		}
		
		return rowsUpdated;
		
		
		
	}

	public int insert(Movie movie, Connection con) throws MovieException, SQLException {

		LinkedList<Movie> movieList = new LinkedList<Movie>();
		
		if((movieList = listByMovieName.get(movie.getMoviename())) != null) {
			
			System.out.println("Entered in list");
			
			Iterator it = movieList.iterator();
			while(it.hasNext()) {
				
				System.out.println("Movie Banner: " );
				if(movie.getMoviebanner().equals(((Movie)it.next()).getMoviebanner())) {
					throw new MovieException("Duplicate Movie");
				}
			}
		}
		
		PreparedStatement ps = null;
		
			ps = con.prepareStatement("insert into MOVIE( MOVIENAME, MOVIEBANNER, RELEASEDATE, RENTAMOUNT, CATEGORY, COPIESAVAILABLE) values (?, ?, ?, ?, ?, ?)");
			ps.setString(1, movie.getMoviename());
			ps.setString(2, movie.getMoviebanner());
			ps.setDate(3, DateConvert.convertUtilToSQLdate(movie.getReleasedate()));
			ps.setFloat(4, movie.getRentamount());
			ps.setString(5, movie.getCategory());
			ps.setInt(6, movie.getCopiesavailable());

			int result=ps.executeUpdate();
			if(result <= 0)
			{
				throw new MovieException("Failed to insert movie in the system.");
			}
			
			//con.commit();
			
			String SQL_STATEMENT = "Select movieId from movie where movieName = ? and movieBanner = ?";
			
			ps = con.prepareStatement(SQL_STATEMENT);
			ps.setString(1, movie.getMoviename());
			ps.setString(2, movie.getMoviebanner());
			ResultSet rs = ps.executeQuery();
			rs.next();
			movie.setMovieid(rs.getInt("movieId"));
			System.out.println("Movie Infor: " + movie.toString());
			listByMovieId.put(movie.getMovieid(), movie);
			
			
			if(!listByMovieName.containsKey(movie.getMoviename())) {
				movieList = new LinkedList<Movie>();
				movieList.add(movie);
				listByMovieName.put(movie.getMoviename(), movieList);
			}
			else
			{
				listByMovieName.get(movie.getMoviename()).add(movie);
			}
			if(!listByMovieBanner.containsKey(movie.getMoviebanner())) {
				movieList = new LinkedList<Movie>();
				movieList.add(movie);
				listByMovieBanner.put(movie.getMoviebanner(), movieList);
			}
			else
			{
				listByMovieBanner.get(movie.getMoviebanner()).add(movie);
			}
			if(!listByMovieCategory.containsKey(movie.getCategory())) {
				movieList = new LinkedList<Movie>();
				movieList.add(movie);
				listByMovieCategory.put(movie.getCategory(), movieList);
			}
			else
			{
				listByMovieCategory.get(movie.getCategory()).add(movie);
			}
			
			return result;
	}

	public Movie findByMovieId(int movieid, Connection con)
			throws MovieException, SQLException {
		Movie movie=listByMovieId.get(movieid);
		if(movie==null)
		{
			PreparedStatement stmt = null;
			ResultSet rs = null;
			String SQL_STATEMENT = "Select movieId, movieName, movieBanner, releaseDate, rentAmount, category, copiesAvailable from movie where movieId = ?";
		
			stmt = con.prepareStatement(SQL_STATEMENT);
			stmt.setInt(1, movieid);
			rs = stmt.executeQuery();
			movie = fetchSingleResult(rs);
			if(movie != null) { 
				listByMovieId.put(movieid, movie);
				
			}
			else {
				throw new MovieException("No movie found the system");
			}
			
		}
		return movie;
		
		
	}

	public Movie[] findByMoviename(String moviename, Connection con)
			throws MovieException, SQLException {
		
		if(listByMovieName.containsKey(moviename)) {
			int size=listByMovieName.get(moviename).size();
			Movie[] movieList = listByMovieName.get(moviename).toArray(new Movie[size]);
			return movieList;
		}
		
		
		PreparedStatement stmt = null;
		ResultSet rs = null;
		String SQL_STATEMENT = "Select movieId, movieName, movieBanner, releaseDate, rentAmount, category, copiesAvailable from movie where movieName = ? order by movieName";
		
			stmt = con.prepareStatement(SQL_STATEMENT);
			stmt.setString(1, moviename);
			rs = stmt.executeQuery();
			if(rs != null)
			{
				if(rs.getRow()==0)
				{
					throw new MovieException("No movie found the system");
				}
				return fetchMultiResults(rs);
			}
			else
			{
				throw new MovieException("No movie found the system");
			}
		
		
		
	
	}

	public Movie[] findByMoviebanner(String moviebanner, Connection con)
			throws MovieException, SQLException {
		
		if(listByMovieBanner.containsKey(moviebanner)) {
			int size=listByMovieBanner.get(moviebanner).size();
			Movie[] movieList = listByMovieBanner.get(moviebanner).toArray(new Movie[size]);
			return movieList;
		}
		
		
		PreparedStatement stmt = null;
		ResultSet rs = null;
		String SQL_STATEMENT = "Select movieId, movieName, movieBanner, releaseDate, rentAmount, category, copiesAvailable from movie where movieBanner = ? order by movieBanner";
		
			stmt = con.prepareStatement(SQL_STATEMENT);
			stmt.setString(1, moviebanner);
			rs = stmt.executeQuery();
			if(rs != null)
			{
				if(rs.getRow()==0)
				{
					throw new MovieException("No movie found the system");
				}
				return fetchMultiResults(rs);
			}
			else
			{
				throw new MovieException("No movie found the system");
			}
		
		
		
	}

	
	public Movie[] findByCategory(String category, Connection con)
			throws MovieException, SQLException {
		if(listByMovieCategory.containsKey(category)) {
			int size=listByMovieCategory.get(category).size();
			Movie[] movieList = listByMovieCategory.get(category).toArray(new Movie[size]);
			return movieList;
		}
		
		
		PreparedStatement stmt = null;
		ResultSet rs = null;
		String SQL_STATEMENT = "Select movieId, movieName, movieBanner, releaseDate, rentAmount, category, copiesAvailable from movie where category = ? order by category";
		
			stmt = con.prepareStatement(SQL_STATEMENT);
			stmt.setString(1, category);
			rs = stmt.executeQuery();
			if(rs != null)
			{
				if(rs.getRow()==0)
				{
					throw new MovieException("No movie found the system");
				}
				return fetchMultiResults(rs);
			}
			else
			{
				throw new MovieException("No movie found the system");
			}
		
		
		
	}

	public Movie[] findAll(Connection con) throws MovieException, SQLException {
		int size = listByMovieId.size();
		Movie movieList[] = listByMovieId.values().toArray(new Movie[size]);
		System.out.println("Movies List : " + movieList.toString());
		if (movieList == null || movieList.length <= 0)
		{
			PreparedStatement stmt = null;
			ResultSet rs = null;
			String SQL_STATEMENT = "Select movieId, movieName, movieBanner, releaseDate, rentAmount, category, copiesAvailable from movie";
			
			stmt = con.prepareStatement(SQL_STATEMENT);
			rs = stmt.executeQuery();
			if(rs!=null)
			{
				return fetchMultiResults(rs);
			}
			else
			{
			
			throw new MovieException("No Movies found in the system.");
			}
		}
		return movieList;
		
		
		
	}

	public Movie[] findExecutingUserSelect(String selectStatement,
			Object[] sqlParams, Connection con) throws MovieException {
		PreparedStatement stmt = null;
		ResultSet rs = null;
		final String SQL_STATEMENT = selectStatement;
		try {
			stmt = con.prepareStatement(SQL_STATEMENT);
			for (int i = 0; i < sqlParams.length; i++) {
				stmt.setObject(i + 1, sqlParams[i]);
			}
			rs = stmt.executeQuery();
			return fetchMultiResults(rs);
		} catch (SQLException sqle) {
			throw new MovieException(sqle);
		} catch (Exception e) {
			throw new MovieException(e);
		} finally {
		}
	}

	public Movie[] findExecutingUserWhere(String whereClause,
			Object[] sqlParams, Connection con) throws MovieException {
		PreparedStatement stmt = null;
		ResultSet rs = null;
		String SQL_SELECT = "Select movieId, movieName, movieBanner, releaseDate, rentAmount, category, copiesAvailable from movie";
		final String SQL_STATEMENT = SQL_SELECT + " where " + whereClause;
		try {
			stmt = con.prepareStatement(SQL_STATEMENT);
			for (int i = 0; i < sqlParams.length; i++) {
				stmt.setObject(i + 1, sqlParams[i]);
			}
			rs = stmt.executeQuery();
			return fetchMultiResults(rs);
		} catch (SQLException sqle) {
			throw new MovieException(sqle);
		} catch (Exception e) {
			throw new MovieException(e);
		} finally {
		}
	}

	protected Movie fetchSingleResult(ResultSet rs) throws SQLException {
		if (rs.next()) {
			Movie dto = new Movie();
			populateVO(dto, rs);
			return dto;
		} else {
			return null;
		}
	}

	protected void populateVO(Movie dto, ResultSet rs) throws SQLException {
		dto.setMovieid(rs.getInt("movieId"));
		dto.setMoviename(rs.getString("movieName"));
		dto.setMoviebanner(rs.getString("movieBanner"));
		dto.setReleasedate(DateConvert.convertSQLToUtilDate(rs.getDate("releaseDate")));
		dto.setRentamount(rs.getInt("rentAmount"));
		dto.setCategory(rs.getString("category"));
		dto.setCopiesavailable(rs.getInt("copiesAvailable"));
	}

	protected Movie[] fetchMultiResults(ResultSet rs) throws SQLException {
		Collection<Movie> resultList = new ArrayList<Movie>();
		while (rs.next()) {
			Movie dto = new Movie();
			populateVO(dto, rs);
			resultList.add(dto);
		}
		Movie ret[] = new Movie[resultList.size()];
		resultList.toArray(ret);
		return ret;
	}
}
